// from https://github.com/JanLoebel/showdown-toc

// Extension loading compatible with AMD and CommonJs
(function(extension) {
	'use strict';

	if (typeof showdown === 'object') {
		// global (browser or nodejs global)
		showdown.extension('toc', extension());
	} else if (typeof define === 'function' && define.amd) {
		// AMD
		define('toc', extension());
	} else if (typeof exports === 'object') {
		// Node, CommonJS-like
		module.exports = extension();
	} else {
		// showdown was not found so we throw
		throw Error('Could not find showdown library');
	}

}(function() {

	function getHeaderEntries(sourceHtml) {
		if (typeof window === 'undefined') {
			return getHeaderEntriesInNodeJs(sourceHtml);
		} else {
			return getHeaderEntriesInBrowser(sourceHtml);
		}
	}

	function getHeaderEntriesInNodeJs(sourceHtml) {
		var cheerio = require('cheerio');
		var $ = cheerio.load(sourceHtml);
		var headers = $('h1, h2, h3, h4, h5, h6');

		var headerList = [];
		for (var i = 0; i < headers.length; i++) {
			var el = headers[i];
			headerList.push(new TocEntry(el.name, $(el).text(), $(el).attr('id')));
		}

		return headerList;
	}

	function getHeaderEntriesInBrowser(sourceHtml) {
		// Generate dummy element
		var source = document.createElement('div');
		source.innerHTML = sourceHtml;

		// Find headers
		var headers = source.querySelectorAll('h1, h2, h3, h4, h5, h6');
		var headerList = [];
		for (var i = 0; i < headers.length; i++) {
			var el = headers[i];
			headerList.push(new TocEntry(el.tagName, el.textContent, el.id));
		}

		return headerList;
	}

	function TocEntry(tagName, text, anchor) {
		this.tagName = tagName;
		this.text = text;
		this.anchor = anchor;
		this.children = [];
	}

	TocEntry.prototype.childrenToString = function() {
		if (this.children.length === 0) {
			return "";
		}
		var result = "<ul>\n";
		for (var i = 0; i < this.children.length; i++) {
			result += this.children[i].toString();
		}
		result += "</ul>\n";
		return result;
	};

	TocEntry.prototype.toString = function() {
		var result = "<li>";
		if (this.text) {
			result += "<a href=\"#" + this.anchor + "\">" + this.text + "</a>";
		}
		result += this.childrenToString();
		result += "</li>\n";
		return result;
	};

	function sortHeader(tocEntries, level) {
		level = level || 1;
		var tagName = "H" + level,
			result = [],
			currentTocEntry;

		function push(tocEntry) {
			if (tocEntry !== undefined) {
				if (tocEntry.children.length > 0) {
					tocEntry.children = sortHeader(tocEntry.children, level + 1);
				}
				result.push(tocEntry);
			}
		}

		for (var i = 0; i < tocEntries.length; i++) {
			var tocEntry = tocEntries[i];
			if (tocEntry.tagName.toUpperCase() !== tagName) {
				if (currentTocEntry === undefined) {
					currentTocEntry = new TocEntry();
				}
				currentTocEntry.children.push(tocEntry);
			} else {
				push(currentTocEntry);
				currentTocEntry = tocEntry;
			}
		}

		push(currentTocEntry);
		return result;
	}

	return [{
		type: 'output',
		filter: function(sourceHtml) {
			var headerList = getHeaderEntries(sourceHtml);

			// No header found
			if (headerList.length === 0) {
				return sourceHtml;
			}

			// Sort header
			headerList = sortHeader(headerList);

			// Build result and replace all [toc]
			var result = '<div class="toc">\n<ul>\n' + headerList.join("") + '</ul>\n</div>\n';
			return sourceHtml.replace(/\[toc\]/gi, result);
		}
	}];
}));
